using System;

using Lucene.Net.Index;
using Lucene.Net.Documents;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using System.Xml;
using System.Collections;
using System.Text.RegularExpressions;
using System.IO;

namespace umbSearch.businessLogic
{
	/// <summary>
	/// Summary description for Indexer.
	/// </summary>
	public class Indexer
	{
		public Indexer()
		{
			//
			// TODO: Add constructor logic here
			//
		}
	
		public static string Index() 
		{
			// index
			DateTime searchStart = DateTime.Now;
			int counter = 0;
			string[] excludeIds = Settings.ExcludeIds.Split(";".ToCharArray());
			IndexWriter writer = new IndexWriter(Settings.IndexDirectory, new StandardAnalyzer(), true);

			XmlDocument x = umbraco.content.xmlContent;
			foreach (XmlNode n in x.GetElementsByTagName("node")) 
			{
				if (AddNodeToIndex(n, writer, excludeIds)) 
					counter++;
			}
			writer.Optimize();
			writer.Close();
			TimeSpan searchEnd = DateTime.Now.Subtract(searchStart);
			string searchTotal = searchEnd.Seconds + ".";
			for (int i=4;i>searchEnd.Milliseconds.ToString().Length;i--)
				searchTotal += "0";
			searchTotal += searchEnd.Milliseconds.ToString();
			return counter.ToString() + " nodes indexed in " + searchTotal + " second(s)";

		}	

		public static bool AddPageToIndex(int PageID) 
		{
			try 
			{
				XmlNode n = umbraco.content.xmlContent.GetElementById(PageID.ToString());
				
				// Remove document
				IndexReader ir = IndexReader.Open(Settings.IndexDirectory);
				ir.Delete(new Term("id", n.Attributes.GetNamedItem("id").Value));
				ir.Close();

				// Add document
				IndexWriter writer = new IndexWriter(Settings.IndexDirectory, new StandardAnalyzer(), false);
				AddNodeToIndex(n, writer, Settings.ExcludeIds.Split(";".ToCharArray()));
				writer.Optimize();
				writer.Close();
				return true;
			} 
			catch (Exception ee)
			{
                Alerts.Alert(String.Format("Error deleting page with id {0}\n\nFull error message:\n{1}", PageID.ToString(), ee.ToString()));
				umbraco.BusinessLogic.Log.Add(umbraco.BusinessLogic.LogTypes.Error, new umbraco.BusinessLogic.User(0), PageID, ee.ToString());
				return false;
			}
		}

		public static bool AddNodeToIndex(XmlNode n, IndexWriter writer, string[] excludeIds) 
		{
			Hashtable _fields = new Hashtable();
			bool _succes = false;
			bool excludeNode = false;
			for (int i=0;i<excludeIds.Length;i++)
				if ((","+n.Attributes.GetNamedItem("path").Value+",").IndexOf("," + excludeIds[i] + ",") > -1)
					excludeNode = true;

			// Test for access
			if (umbraco.library.IsProtected(int.Parse(n.Attributes.GetNamedItem("id").Value), n.Attributes.GetNamedItem("path").Value))
				excludeNode = true;

			// Test for nodeType
			if (!excludeNode && ((";" + Settings.ExcludeNodeTypes + ";").IndexOf(";"+n.Attributes.GetNamedItem("nodeTypeAlias").Value+";") < 0 || n.Attributes.GetNamedItem("nodeTypeAlias").Value == "")) 
			{
				try 
				{
					bool _naviHide = false;
					string contents = n.Attributes.GetNamedItem("nodeName").Value + " ";
					foreach (XmlNode content in n.SelectNodes("./data"))
						if (Settings.ExcludeUmbracoNaviHide && content.ChildNodes.Count > 0 && content.Attributes.GetNamedItem("alias").Value.ToLower() == "umbraconavihide") 
						{
							if (content.FirstChild.Value != "") 
							{
								if (content.FirstChild.Value == "1")
									_naviHide = true;
							}
						} 
						else if (content.ChildNodes.Count > 0 && ((";"+Settings.IndexDataWithAliases+";").IndexOf(";" + content.Attributes.GetNamedItem("alias").Value+";") > -1 || (";" + Settings.IndexFilesWithAliases + ";").IndexOf(";" + content.Attributes.GetNamedItem("alias").Value + ";") > -1)) 
						{
                            string contentValue = content.FirstChild.Value;

                            // Check for multimedia/file indexing
                            if ((";" + Settings.IndexFilesWithAliases + ";").IndexOf(";" + content.Attributes.GetNamedItem("alias").Value + ";") > -1)
                            {
                                try
                                {
                                    // Test for media picker
                                    int mediaPickerId;
                                    if (int.TryParse(contentValue, out mediaPickerId))
                                        contentValue = new umbraco.cms.businesslogic.media.Media(mediaPickerId).getProperty("umbracoFile").Value.ToString();

                                    string fileExt = contentValue.Substring(contentValue.LastIndexOf(".") + 1, contentValue.Length - contentValue.LastIndexOf(".") - 1).ToLower();
                                    interfaces.IUmbracoSearchFileFilter filter = businessLogic.FileFilterFactory.GetFilter(fileExt);
                                    contentValue = filter.returnText(System.Web.HttpContext.Current.Server.MapPath(contentValue));
                                }
                                catch (Exception e)
                                {
                                    umbraco.BusinessLogic.Log.Add(umbraco.BusinessLogic.LogTypes.Error, new umbraco.BusinessLogic.User(0), int.Parse(n.Attributes.GetNamedItem("id").Value), String.Format("Error indexing file: {0}\n\nFull error message:\n{1}", contentValue, e.ToString()));
                                    Alerts.Alert(String.Format("Error indexing file: {0}\n\nFull error message:\n{1}", contentValue, e.ToString()));
                                }
                            }

                            _fields.Add(content.Attributes.GetNamedItem("alias").Value, contentValue);
                            contents += contentValue + " \n";
						} 

					if (!_naviHide) 
					{
						_succes = true;
						DeleteFromIndex(int.Parse(n.Attributes.GetNamedItem("id").Value));

						// Some might not have a writer name
						string writerName = "";
						try 
						{
							writerName = n.Attributes.GetNamedItem("writerName").Value.ToString();
						} 
						catch {}
						AddDoc(writer, DateTime.Parse(n.Attributes.GetNamedItem("updateDate").Value.ToString()), contents, n.Attributes.GetNamedItem("id").Value.ToString(), n.Attributes.GetNamedItem("nodeName").Value.ToString(), writerName, n.Attributes.GetNamedItem("path").Value, _fields);
					}
				} 
				catch (Exception err) 
				{
					System.Web.HttpContext.Current.Trace.Warn("umbSearch", err.ToString());
				}
			}
			return _succes;
		}

		private static void AddDoc(IndexWriter writer, DateTime createDate, string text, string nodeId, string nodeName, string writerName, string path, Hashtable fields)
		{

			Document d = new Document();
			d.Add(new Field("contents", text, true, true, true));
			d.Add(new Field("id", nodeId, true, true, true));
			d.Add(new Field("name", nodeName, true, true, true));
			d.Add(new Field("updateDate", createDate.ToString("s"), true, true, true));
			d.Add(new Field("writerName", writerName, true, true, true));
			d.Add(new Field("path", (path.Replace("-1,", "")+",").Replace(",",Settings.PathSplit), true, true, true));

			// Add custom fields
			IDictionaryEnumerator id = fields.GetEnumerator();
			while (id.MoveNext())
				d.Add(new Field(id.Key.ToString(), id.Value.ToString(), true, true, true));

			writer.AddDocument(d);
			
		}

		private void addDocument(IndexWriter writer, string path)
		{
			Document doc = new Document();
			StreamReader sr = new StreamReader(path, System.Text.Encoding.Default);
			doc.Add(Field.Text("contents", sr));
			doc.Add(Field.Text("filename", path));
			writer.AddDocument(doc);
			sr.Close();
		}

		public static bool DeleteFromIndex(int PageID) 
		{
			try 
			{
				IndexReader ir = IndexReader.Open(Settings.IndexDirectory);
				ir.Delete(new Term("id", PageID.ToString()));
				ir.Close();
				return true;
			} 
			catch (Exception ee)
			{
                // Alert
                Alerts.Alert(String.Format("Error deleting page with id {0}\n\nFull error message:\n{1}", PageID.ToString(), ee.ToString()));

				return false;
			}
		}


	}
}
